/**
 * This base class is used to handle data preparation (e.g., sorting, filtering
 * and group summary).
 */
Ext.define('Ext.ux.ajax.DataSimlet', function() {

	function makeSortFn(def, cmp) {
		var order = def.direction, sign = (order && order.toUpperCase() == 'DESC')
				? -1
				: 1;

		return function(leftRec, rightRec) {
			var lhs = leftRec[def.property], rhs = rightRec[def.property], c = (lhs < rhs)
					? -1
					: ((rhs < lhs) ? 1 : 0);

			if (c || !cmp) {
				return c * sign;
			}

			return cmp(leftRec, rightRec);
		};
	}

	function makeSortFns(defs, cmp) {
		for (var sortFn = cmp, i = defs && defs.length; i;) {
			sortFn = makeSortFn(defs[--i], sortFn);
		}
		return sortFn;
	}

	return {
		extend : 'Ext.ux.ajax.Simlet',

		getData : function(ctx) {
			var me = this, data = me.data, params = ctx.params, order = (params.group || '')
					+ '-' + (params.sort || '') + '-' + (params.dir || ''), fields, sortFn;

			if (!order) {
				return data;
			}

			ctx.groupSpec = params.group && Ext.decode(params.group);
			if (order == me.currentOrder) {
				return me.sortedData;
			}

			fields = params.sort;
			if (params.dir) {
				fields = [{
							direction : params.dir,
							property : fields
						}];
			} else {
				fields = Ext.decode(params.sort);
			}

			sortFn = makeSortFns((ctx.sortSpec = fields));
			sortFn = makeSortFns(ctx.groupSpec, sortFn);

			data = data.slice(0); // preserve 'physical' order of raw data...
			if (sortFn) {
				Ext.Array.sort(data, sortFn);
			}

			me.sortedData = data;
			me.currentOrder = order;

			return data;
		},

		getPage : function(ctx, data) {
			var ret = data, length = data.length, start = ctx.params.start || 0, end = ctx.params.limit
					? Math.min(length, start + ctx.params.limit)
					: length;

			if (start || end < length) {
				ret = ret.slice(start, end);
			}

			return ret;
		},

		getGroupSummary : function(groupField, rows, ctx) {
			return rows[0];
		},

		getSummary : function(ctx, data, page) {
			var me = this, groupField = ctx.groupSpec[0].property, accum = null, todo = {}, summary = [], fieldValue, lastFieldValue;

			Ext.each(page, function(rec) {
						fieldValue = rec[groupField];
						todo[fieldValue] = true;
					});

			function flush() {
				if (accum) {
					summary.push(me.getGroupSummary(groupField, accum, ctx));
					accum = null;
				}
			}

			// data is ordered primarily by the groupField, so one pass can pick
			// up all
			// the summaries one at a time.
			Ext.each(data, function(rec) {
						fieldValue = rec[groupField];

						if (lastFieldValue !== fieldValue) {
							flush();
							lastFieldValue = fieldValue;
						}

						if (!todo[fieldValue]) {
							// if we have even 1 summary, we have summarized all
							// that we need
							// (again because data and page are ordered by
							// groupField)
							return !summary.length;
						}

						if (accum) {
							accum.push(rec);
						} else {
							accum = [rec];
						}

						return true;
					});

			flush(); // make sure that last pesky summary goes...

			return summary;
		}
	};
}());
